﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;

namespace RevitToOSG
{
    class getGeometry
    {
        public static void AddCurvesAndSolids(GeometryElement geomElem,List<Curve> curves,List<Mesh> meshes,List<Solid> solids)
        {
            foreach(GeometryObject geomObject in geomElem)
            {
                Curve curve = geomObject as Curve;
                if(null != curve)
                {
                    curves.Add(curve);
                    continue;
                }

                Mesh mesh = geomObject as Mesh;
                if (null != mesh)
                {
                    meshes.Add(mesh);
                    continue;
                }

                Solid solid = geomObject as Solid;
                if(null != solid)
                {
                    if (null == solid || 0 == solid.Faces.Size || 0 == solid.Edges.Size)  //去掉空实体
                    {
                        continue;
                    }
                    solids.Add(solid);
                    continue;
                }
                //如果GeometryObject是几何实例，则进行第二次遍历
                GeometryInstance geomInst = geomObject as GeometryInstance;
                if(null !=geomInst)
                {
                    AddCurvesAndSolids(geomInst.GetSymbolGeometry(geomInst.Transform), curves, meshes, solids);
                }
            }
        }

        public static void AddVerticesAndNormalsOfSolid(Solid solid,List<XYZ> vertices,List<XYZ> normals)
        {
            if (solid != null)
            {

                foreach (Face face in solid.Faces)  //对每个面做循环取值
                {
                    PlanarFace planarFace = face as PlanarFace;  //将面转换为平面，并获取顶点法线
                    if (planarFace != null)  //判断是否为planarface（可能为其他类型的面，此时转换就会失败）
                    {
                        XYZ faceNormal = planarFace.FaceNormal;

                        Mesh mesh = face.Triangulate();  //对面获取三角面片的顶点坐标
                        if(mesh != null)//判断是否为mesh
                        {
                            for (int i = 0; i < mesh.NumTriangles; ++i)  //对于每个面中的三角面片，将其顶点坐标和法线写入文件
                            {
                                MeshTriangle triangle = mesh.get_Triangle(i);
                                for (int j = 0; j < 3; ++j)
                                {
                                    vertices.Add(triangle.get_Vertex(j));
                                }

                                for (int j = 0; j < 3; ++j)
                                {
                                    normals.Add(faceNormal);
                                }
                            }
                        }
                        
                    }

                    CylindricalFace cylindricalFace = face as CylindricalFace;  //将面转换为圆柱面，并获取顶点法线
                    if (cylindricalFace != null)  //判断是否为CylindricalFace（可能为其他类型的面，此时转换就会失败）
                    {
                        Mesh mesh = face.Triangulate();  //对面获取三角面片的顶点坐标
                        if (mesh != null)//判断是否为mesh
                        {
                            for (int i = 0; i < mesh.NumTriangles; ++i)  //对于每个面中的三角面片，将其顶点坐标和法线写入文件
                            {
                                MeshTriangle triangle = mesh.get_Triangle(i);
                                for (int j = 0; j < 3; ++j)
                                {
                                    vertices.Add(triangle.get_Vertex(j));
                                }

                                for (int j = 0; j < 3; ++j)
                                {
                                    normals.Add(ComputeNormal(triangle));
                                }
                            }
                        }
                    }
                }
            }
        }

        public static void AddVerticesAndNormalsOfMesh(Mesh mesh, List<XYZ> vertices, List<XYZ> normals)
        {
            if (mesh != null)//判断是否为mesh
            {
                for (int i = 0; i < mesh.NumTriangles; ++i)  //对于每个面中的三角面片，将其顶点坐标和法线写入文件
                {
                    MeshTriangle triangle = mesh.get_Triangle(i);
                    for (int j = 0; j < 3; ++j)
                    {
                        vertices.Add(triangle.get_Vertex(j));
                    }

                    for (int j = 0; j < 3; ++j)
                    {
                        normals.Add(ComputeNormal(triangle));
                    }
                }
            }
        }

        public static int AddVerticesOfCurve(Curve curve, List<XYZ> points)
        {
            int num = 0;  //记录每条线的顶点数量
            if(curve != null)
            {
                foreach(XYZ point in curve.Tessellate())  //将曲线细分化后得到的每个点加入到顶点数组中
                {
                    points.Add(point);
                    ++num;
                }
            }
            return num;
        }

        public static XYZ ComputeNormal(MeshTriangle triangle) //由三角面片三顶点计算面法线
        {
            XYZ v1, v2, v3;            
            v1 = triangle.get_Vertex(0);
            v2 = triangle.get_Vertex(1);
            v3 = triangle.get_Vertex(2);

            //由三点计算法线
            double na = (v2.Y - v1.Y) * (v3.Z - v1.Z) - (v2.Z - v1.Z) * (v3.Y - v1.Y);
            double nb = (v2.Z - v1.Z) * (v3.X - v1.X) - (v2.X - v1.X) * (v3.Z - v1.Z);
            double nc = (v2.X - v1.X) * (v3.Y - v1.Y) - (v2.Y - v1.Y) * (v3.X - v1.X);

            //对法线归一化 
            XYZ normal = new XYZ(na / (Math.Sqrt(na * na + nb * nb + nc * nc)), 
                                 nb / (Math.Sqrt(na * na + nb * nb + nc * nc)),
                                 nc / (Math.Sqrt(na * na + nb * nb + nc * nc)));
            return normal;
        }

       
    }
}
